package window;

import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.KeyStroke;
import javax.swing.SizeRequirements;
import javax.swing.text.DefaultCaret;
import javax.swing.text.Element;
import javax.swing.text.ParagraphView;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.InlineView;

/**
 *
 * @author Simão Reis
 * @author João Reis
 */
public class ChatWindow extends javax.swing.JFrame {

    /**
     * Creates new form ChatWindow
     */
    public ChatWindow() {
        initComponents();
        try {
            udpSocket = new DatagramSocket(8080);
        } catch (SocketException ex) {
            Logger.getLogger(ChatWindow.class.getName()).log(Level.SEVERE, null, ex);
        }
        readMessages = "";
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jFrame1 = new javax.swing.JFrame();
        chatPanel = new javax.swing.JPanel();
        avatarLabel = new javax.swing.JLabel();
        sendButton = new javax.swing.JButton();
        sendScrollPane = new javax.swing.JScrollPane();
        sendTextArea = new javax.swing.JTextArea();
        addressTextField = new javax.swing.JTextField();
        addressLabel = new javax.swing.JLabel();
        usernameLabel = new javax.swing.JTextField();
        readScrollPane = new javax.swing.JScrollPane();
        readTextPane = new javax.swing.JTextPane();

        javax.swing.GroupLayout jFrame1Layout = new javax.swing.GroupLayout(jFrame1.getContentPane());
        jFrame1.getContentPane().setLayout(jFrame1Layout);
        jFrame1Layout.setHorizontalGroup(
            jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        jFrame1Layout.setVerticalGroup(
            jFrame1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        chatPanel.setPreferredSize(new java.awt.Dimension(470, 300));

        avatarLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/picture/dummy.jpg"))); // NOI18N

        sendButton.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
        sendButton.setText("Enviar");
        sendButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButtonActionPerformed(evt);
            }
        });

        sendTextArea.setColumns(20);
        sendTextArea.setLineWrap(true);
        sendTextArea.setRows(5);
        InputMap input = sendTextArea.getInputMap();
        KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
        KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
        input.put(shiftEnter, "insert-break");  // input.get(enter)) = "insert-break"
    input.put(enter, "text-submit");

    ActionMap actions = sendTextArea.getActionMap();
    actions.put("text-submit", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            send();
        }
    });
    sendScrollPane.setViewportView(sendTextArea);

    addressLabel.setText("IP Address");

    usernameLabel.setHorizontalAlignment(javax.swing.JTextField.CENTER);

    readScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    readScrollPane.setAutoscrolls(true);

    readTextPane.setEditable(false);
    readTextPane.setContentType("text/html"); // NOI18N
    readTextPane.setEditorKit(new HTMLEditorKit(){ 
        @Override 
        public ViewFactory getViewFactory(){ 

            return new HTMLFactory(){ 
                public View create(Element e){ 
                    View v = super.create(e); 
                    if(v instanceof InlineView){ 
                        return new InlineView(e){ 
                            public int getBreakWeight(int axis, float pos, float len) { 
                                return GoodBreakWeight; 
                            } 
                            public View breakView(int axis, int p0, float pos, float len) { 
                                if(axis == View.X_AXIS) { 
                                    checkPainter(); 
                                    int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len); 
                                    if(p0 == getStartOffset() && p1 == getEndOffset()) { 
                                        return this; 
                                    } 
                                    return createFragment(p0, p1); 
                                } 
                                return this; 
                            } 
                        }; 
                    } 
                    else if (v instanceof ParagraphView) { 
                        return new ParagraphView(e) { 
                            protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) { 
                                if (r == null) { 
                                    r = new SizeRequirements(); 
                                } 
                                float pref = layoutPool.getPreferredSpan(axis); 
                                float min = layoutPool.getMinimumSpan(axis); 
                                // Don't include insets, Box.getXXXSpan will include them. 
                                r.minimum = (int)min; 
                                r.preferred = Math.max(r.minimum, (int) pref); 
                                r.maximum = Integer.MAX_VALUE; 
                                r.alignment = 0.5f; 
                                return r; 
                            } 

                        }; 
                    } 
                    return v; 
                } 
            }; 
        } 
    });
    DefaultCaret caret = (DefaultCaret)readTextPane.getCaret();
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
    readScrollPane.setViewportView(readTextPane);

    javax.swing.GroupLayout chatPanelLayout = new javax.swing.GroupLayout(chatPanel);
    chatPanel.setLayout(chatPanelLayout);
    chatPanelLayout.setHorizontalGroup(
        chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(chatPanelLayout.createSequentialGroup()
            .addContainerGap()
            .addGroup(chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(chatPanelLayout.createSequentialGroup()
                    .addGroup(chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                        .addComponent(avatarLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(usernameLabel))
                    .addGap(18, 18, 18)
                    .addComponent(readScrollPane))
                .addGroup(chatPanelLayout.createSequentialGroup()
                    .addComponent(sendScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 365, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                    .addGroup(chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(addressTextField)
                        .addComponent(sendButton, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
                        .addGroup(chatPanelLayout.createSequentialGroup()
                            .addComponent(addressLabel)
                            .addGap(0, 0, Short.MAX_VALUE)))))
            .addContainerGap())
    );
    chatPanelLayout.setVerticalGroup(
        chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(chatPanelLayout.createSequentialGroup()
            .addContainerGap()
            .addGroup(chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(chatPanelLayout.createSequentialGroup()
                    .addComponent(avatarLabel)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                    .addComponent(usernameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addComponent(readScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 165, javax.swing.GroupLayout.PREFERRED_SIZE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(chatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addComponent(sendScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGroup(chatPanelLayout.createSequentialGroup()
                    .addComponent(sendButton)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(addressLabel)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(addressTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addContainerGap())
    );

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(chatPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addComponent(chatPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 303, javax.swing.GroupLayout.PREFERRED_SIZE)
    );

    pack();
    }// </editor-fold>//GEN-END:initComponents

    private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendButtonActionPerformed
        send();
    }//GEN-LAST:event_sendButtonActionPerformed

    private void send() {
        //String messageText = "<b>" + usernameLabel.getText() + "</b>" + " >> " + sendTextArea.getText().replaceAll("\n", "<p>") + "<p>";
        String messageText = usernameLabel.getText() + " >> " + sendTextArea.getText().replaceAll("\n", "<p>") + "<p>";
        sendTextArea.setText("");
        byte[] data = messageText.getBytes();
        try {
            udpSenderPacket = new DatagramPacket(data, data.length,
                    InetAddress.getByName(addressTextField.getText()), 8080);
        } catch (UnknownHostException ex) {
            Logger.getLogger(ChatWindow.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            udpSocket.send(udpSenderPacket);
            System.out.println("Sending: " + new String(udpSenderPacket.getData()));
        } catch (IOException ex) {
            Logger.getLogger(ChatWindow.class.getName()).log(Level.SEVERE, null, ex);
        }
        messageText = "<b>" + messageText.substring(0, messageText.indexOf(" >> ")) + "</b>" + messageText.substring(messageText.indexOf(" >> "));
        readMessages += messageText;
        readTextPane.setText(readMessages);
        System.out.println(readTextPane.getText());
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ChatWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final ChatWindow cw = new ChatWindow();
                cw.setVisible(true);
                Thread communication;
                communication = new Thread() {
                    @Override
                    public void run() {
                        byte[] stream;
                        while (true) {
                            stream = new byte[1024];
                            cw.udpReceiverPacket = new DatagramPacket(stream, stream.length);
                            try {
                                cw.udpSocket.receive(cw.udpReceiverPacket);
                            } catch (IOException ex) {
                                Logger.getLogger(ChatWindow.class.getName()).log(Level.SEVERE, null, ex);
                            }
                            String messageText = new String(cw.udpReceiverPacket.getData(), 0, cw.udpReceiverPacket.getLength());
                            System.out.println("Receiving: " + messageText);
                            messageText = "<b><font color=\"blue\">" + messageText.substring(0, messageText.indexOf(" >> ")) + "</b></font>" + messageText.substring(messageText.indexOf(" >> "));
                            readMessages += messageText;
                            cw.readTextPane.setText(readMessages);
                        }
                    }
                };
                communication.start();
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel addressLabel;
    private javax.swing.JTextField addressTextField;
    private javax.swing.JLabel avatarLabel;
    private javax.swing.JPanel chatPanel;
    private javax.swing.JFrame jFrame1;
    private javax.swing.JScrollPane readScrollPane;
    private javax.swing.JTextPane readTextPane;
    private javax.swing.JButton sendButton;
    private javax.swing.JScrollPane sendScrollPane;
    private javax.swing.JTextArea sendTextArea;
    private javax.swing.JTextField usernameLabel;
    // End of variables declaration//GEN-END:variables
    private DatagramSocket udpSocket;
    private DatagramPacket udpSenderPacket;
    private DatagramPacket udpReceiverPacket;
    private static String readMessages;
}
